package com.aispeech.asr.webase.component;

import com.aispeech.asr.comm.data.domain.meter.DimensionType;
import com.aispeech.asr.comm.data.domain.meter.Meter;
import com.aispeech.asr.comm.data.domain.meter.MeterType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
@Lazy
public class MeterSyncer {
    @Autowired
    WebClient webClient;
    @Value("${apis.boss-metering-url}")
    private String bossMeteringUrl;

    public void reportSentenceMeter(String productId, long duration) {
        reportSentenceMeter(productId, 1, duration);
    }

    public void reportSentenceMeter(String productId, int frequencies, long duration) {
        sync(MeterType.SENTENCE, productId, frequencies, duration);
    }
    
    public void reportMeter(String meterType, String productId, int frequencies, long duration) {
        sync(meterType, productId, frequencies, duration);
    }

    private void sync(String meterType, String productId, int frequencies, long duration) {
        if (StringUtils.isAnyEmpty(bossMeteringUrl)) {
            log.warn("Not found property: apis.boss-metering-url");
        } else {
            List<Meter> meters = new ArrayList<>();

            if (frequencies > 0) {
                meters.add(Meter.of(meterType, DimensionType.FREQUENCY, productId, frequencies));
            }

            if (duration > 0) {
                meters.add(Meter.of(meterType, DimensionType.PERIOD, productId, duration));
            }

            webClient
                    .post()
                    .uri(bossMeteringUrl)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(meters)
                    .retrieve()
                    .onStatus(HttpStatus::is4xxClientError, this::onException)
                    .onStatus(HttpStatus::is5xxServerError, this::onException)
                    .bodyToMono(String.class)
                    .subscribe(res -> {
                        log.info("[ MeterSyncer.subscribe ] response: {}", res);
                    });
        }
    }

    private Mono<WebClientResponseException> onException(ClientResponse response) {
        return response
                .createException()
                .doOnNext(ex -> log.warn(
                        "[ MeterSyncer.exception ] status: {}, message: {}",
                        ex.getRawStatusCode(),
                        ex.getResponseBodyAsString()
                ));
    }

}
